<template>
  <div class="directives-demo">
    <h2>Vue 3 自定义指令</h2>
    
    <div class="directives-grid">
      <!-- 基础自定义指令 -->
      <div class="directive-card">
        <h3>🎯 基础自定义指令</h3>
        <div class="content">
          <p>Vue 3 允许创建自定义指令，用于直接操作 DOM 元素。</p>
          <div class="demo">
            <div v-highlight class="highlight-demo">
              这个元素应用了 highlight 指令
            </div>
            <button @click="toggleHighlight" class="btn-primary">
              {{ isHighlighted ? '移除高亮' : '应用高亮' }}
            </button>
          </div>
          <CodeBlock 
            :code="highlightDirectiveCode" 
            language="javascript" 
            :showLineNumbers="true" 
            :defaultDarkMode="false"
          />
        </div>
      </div>

      <!-- 带参数的指令 -->
      <div class="directive-card">
        <h3>🎨 带参数的指令</h3>
        <div class="content">
          <p>自定义指令可以接收参数和修饰符，实现更灵活的功能。</p>
          <div class="demo">
            <input 
              v-color:background="colorValue" 
              type="text" 
              placeholder="背景色会随值变化" 
              class="input-field"
            />
            <div class="color-selector">
              <button 
                v-for="color in colors" 
                :key="color" 
                @click="colorValue = color" 
                :class="['color-btn', { active: colorValue === color }]"
                :style="{ backgroundColor: color }"
              ></button>
            </div>
          </div>
          <CodeBlock 
            :code="colorDirectiveCode" 
            language="javascript" 
            :showLineNumbers="true" 
            :defaultDarkMode="false"
          />
        </div>
      </div>

      <!-- 生命周期钩子 -->
      <div class="directive-card">
        <h3>🔄 指令生命周期钩子</h3>
        <div class="content">
          <p>自定义指令提供了多个生命周期钩子函数，用于在不同阶段执行操作。</p>
          <div class="demo">
            <div v-lifecycle-tracker class="lifecycle-demo">
              生命周期指令示例
              <button @click="updateText" class="btn-secondary">更新文本</button>
            </div>
            <div class="logs" v-if="lifecycleLogs.length > 0">
              <h4>指令生命周期日志:</h4>
              <ul>
                <li v-for="(log, index) in lifecycleLogs" :key="index">{{ log }}</li>
              </ul>
            </div>
            <button @click="clearLogs" class="btn-secondary">清除日志</button>
          </div>
          <CodeBlock 
            :code="lifecycleDirectiveCode" 
            language="javascript" 
            :showLineNumbers="true" 
            :defaultDarkMode="false"
          />
        </div>
      </div>

      <!-- 实用指令示例 -->
      <div class="directive-card">
        <h3>🚀 实用指令示例</h3>
        <div class="content">
          <p>一些实际应用场景中的自定义指令示例。</p>
          <div class="demo">
            <div class="practical-examples">
              <div class="example">
                <h4>v-focus</h4>
                <input v-focus type="text" placeholder="页面加载后自动聚焦" class="input-field" />
              </div>
              <div class="example">
                <h4>v-tooltip</h4>
                <button v-tooltip="'这是一个提示信息'" class="btn-primary">
                  悬停查看提示
                </button>
              </div>
              <div class="example">
                <h4>v-click-outside</h4>
                <div class="click-outside-demo">
                  <button @click="showPanel = true" class="btn-secondary">
                    显示面板
                  </button>
                  <div v-if="showPanel" v-click-outside="hidePanel" class="panel">
                    点击面板外部关闭此面板
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import CodeBlock from '@components/CodeBlock.vue'

// 基础指令示例数据
const isHighlighted = ref(true)
const toggleHighlight = () => {
  isHighlighted.value = !isHighlighted.value
}

// 颜色指令数据
const colors = ['#3b82f6', '#ef4444', '#10b981', '#f59e0b', '#8b5cf6']
const colorValue = ref('#3b82f6')

// 生命周期指令数据
const lifecycleLogs = ref([])
const lifecycleText = ref('初始文本')

const updateText = () => {
  lifecycleText.value = `更新的文本 - ${new Date().toLocaleTimeString()}`
}

const clearLogs = () => {
  lifecycleLogs.value = []
}

// 实用指令数据
const showPanel = ref(false)
const hidePanel = () => {
  showPanel.value = false
}

// 代码示例
const highlightDirectiveCode = `// 局部自定义指令定义
const vHighlight = {
  mounted(el) {
    el.style.backgroundColor = '#fef3c7'
    el.style.color = '#92400e'
    el.style.padding = '1rem'
    el.style.borderRadius = '8px'
  },
  unmounted(el) {
    // 清理工作
    el.style.backgroundColor = ''
    el.style.color = ''
    el.style.padding = ''
    el.style.borderRadius = ''
  }
}

// 在模板中使用: <div v-highlight></div>`

const colorDirectiveCode = `// 带参数的指令
const vColor = {
  mounted(el, binding) {
    const type = binding.arg || 'color'
    el.style[type] = binding.value
  },
  updated(el, binding) {
    const type = binding.arg || 'color'
    el.style[type] = binding.value
  }
}`

const lifecycleDirectiveCode = `// 指令的生命周期钩子
const vLifecycleTracker = {
  // 指令绑定到元素时
  mounted(el, binding) {
    log('mounted: 指令已绑定到元素')
  },
  // 元素所在组件更新前
  beforeUpdate(el, binding) {
    log('beforeUpdate: 组件更新前')
  },
  // 元素所在组件更新后
  updated(el, binding) {
    log('updated: 组件已更新')
  },
  // 指令与元素解绑前
  beforeUnmount(el, binding) {
    log('beforeUnmount: 指令即将解绑')
  },
  // 指令与元素解绑后
  unmounted(el, binding) {
    log('unmounted: 指令已解绑')
  }
}`

// 全局注册指令（这里模拟，实际应在main.js中注册）
const log = (message) => {
  lifecycleLogs.value.push(`[${new Date().toLocaleTimeString()}] ${message}`)
  // 保持日志数量在合理范围内
  if (lifecycleLogs.value.length > 10) {
    lifecycleLogs.value.shift()
  }
}

// 在Vue 3 <script setup>中定义局部自定义指令
// 注意：指令名需要以v开头
const vHighlight = {
  mounted(el) {
    el.style.backgroundColor = '#fef3c7'
    el.style.color = '#92400e'
    el.style.padding = '1rem'
    el.style.borderRadius = '8px'
    el.style.fontWeight = '500'
  },
  unmounted(el) {
    el.style.backgroundColor = ''
    el.style.color = ''
    el.style.padding = ''
    el.style.borderRadius = ''
    el.style.fontWeight = ''
  }
}

const vColor = {
  mounted(el, binding) {
    const type = binding.arg || 'color'
    el.style[type] = binding.value
    if (type === 'background') {
      el.style.color = '#fff'
      el.style.padding = '0.5rem'
      el.style.borderRadius = '4px'
    }
  },
  updated(el, binding) {
    const type = binding.arg || 'color'
    el.style[type] = binding.value
  }
}

const vLifecycleTracker = {
  mounted(el) {
    log('mounted: 指令已绑定到元素')
    el.style.border = '2px solid #3b82f6'
    el.style.padding = '1rem'
    el.style.borderRadius = '8px'
  },
  // 移除beforeUpdate和updated钩子，避免递归更新
  // beforeUpdate() {
  //   log('beforeUpdate: 组件更新前')
  // },
  // updated() {
  //   log('updated: 组件已更新')
  // },
  beforeUnmount() {
    // 只在控制台打印，不修改响应式数据
    console.log('beforeUnmount: 指令即将解绑')
  },
  unmounted(el) {
    // 只在控制台打印，不修改响应式数据
    console.log('unmounted: 指令已解绑')
    el.style.border = ''
    el.style.padding = ''
    el.style.borderRadius = ''
  }
}

const vFocus = {
  mounted(el) {
    el.focus()
  }
}

const vTooltip = {
  mounted(el, binding) {
    const tooltipText = binding.value
    const tooltip = document.createElement('div')
    tooltip.textContent = tooltipText
    tooltip.style.cssText = `
      position: absolute;
      background: #1f2937;
      color: white;
      padding: 0.5rem;
      border-radius: 4px;
      font-size: 0.875rem;
      white-space: nowrap;
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.2s;
      z-index: 1000;
    `
    document.body.appendChild(tooltip)
    
    const showTooltip = (e) => {
      const rect = el.getBoundingClientRect()
      tooltip.style.top = `${rect.bottom + window.scrollY + 5}px`
      tooltip.style.left = `${rect.left + window.scrollX + rect.width / 2}px`
      tooltip.style.transform = 'translateX(-50%)'
      tooltip.style.opacity = '1'
    }
    
    const hideTooltip = () => {
      tooltip.style.opacity = '0'
    }
    
    el.addEventListener('mouseenter', showTooltip)
    el.addEventListener('mouseleave', hideTooltip)
    
    el._tooltip = tooltip
    el._showTooltip = showTooltip
    el._hideTooltip = hideTooltip
  },
  unmounted(el) {
    if (el._tooltip) {
      document.body.removeChild(el._tooltip)
      el.removeEventListener('mouseenter', el._showTooltip)
      el.removeEventListener('mouseleave', el._hideTooltip)
      delete el._tooltip
      delete el._showTooltip
      delete el._hideTooltip
    }
  }
}

const vClickOutside = {
  mounted(el, binding) {
    const handler = (e) => {
      if (!el.contains(e.target)) {
        binding.value()
      }
    }
    document.addEventListener('click', handler)
    el._clickOutsideHandler = handler
  },
  unmounted(el) {
    if (el._clickOutsideHandler) {
      document.removeEventListener('click', el._clickOutsideHandler)
      delete el._clickOutsideHandler
    }
  }
}
// 在Vue 3 <script setup>中，局部指令需要以特定方式注册
// 注意：在实际使用中，局部自定义指令应该通过app.directive全局注册
// 或者通过组件选项中的directives属性局部注册

// 为了演示目的，我们创建一个组件内指令系统
// 在Vue 3中，正确的做法是通过app.directive全局注册或在组件选项中注册
// 这里为了演示，我们使用ref和生命周期钩子来模拟指令行为

// 简单的模拟指令应用函数
const applyDirectives = () => {
  // 注意：在实际Vue应用中，指令会由Vue自动处理
  // 这里我们只是为了演示而手动应用一些基本效果
  
  // 应用v-highlight效果
  const highlightEl = document.querySelector('.highlight-demo')
  if (highlightEl && isHighlighted.value) {
    vHighlight.mounted(highlightEl)
  }
  
  // 应用v-focus效果
  const focusEl = document.querySelector('.practical-examples .input-field')
  if (focusEl) {
    vFocus.mounted(focusEl)
  }
  
  // 应用v-lifecycle-tracker效果
  const lifecycleEl = document.querySelector('.lifecycle-demo')
  if (lifecycleEl) {
    vLifecycleTracker.mounted(lifecycleEl)
  }
}

// 在DOM更新后应用指令效果
import { nextTick } from 'vue'
nextTick(() => {
  applyDirectives()
})
</script>

<style scoped>
.directives-demo {
  padding: 2rem;
  max-width: 1200px;
  margin: 0 auto;
}

.directives-demo h2 {
  color: #3b82f6;
  text-align: center;
  margin-bottom: 2rem;
  font-size: 2rem;
}

.directives-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
  gap: 2rem;
}

.directive-card {
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  overflow: hidden;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.directive-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}

.directive-card h3 {
  background: linear-gradient(135deg, #10b981, #34d399);
  color: white;
  margin: 0;
  padding: 1rem;
  font-size: 1.25rem;
}

.content {
  padding: 1.5rem;
}

.content p {
  color: #64748b;
  line-height: 1.6;
  margin-bottom: 1.5rem;
}

.demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.btn-primary {
  background: #10b981;
  color: white;
  border: none;
  padding: 0.75rem 1.5rem;
  border-radius: 6px;
  cursor: pointer;
  font-weight: 500;
  transition: background-color 0.2s;
}

.btn-primary:hover {
  background: #059669;
}

.btn-secondary {
  background: #64748b;
  color: white;
  border: none;
  padding: 0.75rem 1.5rem;
  border-radius: 6px;
  cursor: pointer;
  font-weight: 500;
  transition: background-color 0.2s;
}

.btn-secondary:hover {
  background: #475569;
}

.highlight-demo {
  text-align: center;
  margin-bottom: 1rem;
  transition: all 0.3s ease;
}

.input-field {
  padding: 0.75rem;
  border: 1px solid #cbd5e1;
  border-radius: 6px;
  font-size: 1rem;
  width: 100%;
}

.input-field:focus {
  outline: none;
  border-color: #10b981;
  box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
}

.color-selector {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.color-btn {
  width: 30px;
  height: 30px;
  border: 2px solid transparent;
  border-radius: 50%;
  cursor: pointer;
  transition: all 0.2s;
}

.color-btn.active {
  border-color: #1f2937;
  transform: scale(1.2);
}

.lifecycle-demo {
  transition: all 0.3s ease;
}

.logs {
  background: #f8fafc;
  border-radius: 8px;
  padding: 1rem;
  max-height: 200px;
  overflow-y: auto;
}

.logs h4 {
  margin-top: 0;
  color: #334155;
  font-size: 1rem;
}

.logs ul {
  margin: 0;
  padding-left: 1.5rem;
}

.logs li {
  color: #64748b;
  font-size: 0.875rem;
  margin-bottom: 0.25rem;
}

.code-block {
  background: #1e293b;
  border-radius: 8px;
  padding: 1rem;
  overflow-x: auto;
}

.code-block code {
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 0.875rem;
  color: #e2e8f0;
  line-height: 1.5;
}

.practical-examples {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.example {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.example h4 {
  margin: 0;
  color: #334155;
  font-size: 1rem;
}

.click-outside-demo {
  position: relative;
}

.panel {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 0.5rem;
  background: white;
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  padding: 1rem;
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
  min-width: 200px;
}

@media (max-width: 768px) {
  .directives-demo {
    padding: 1rem;
  }
  
  .directives-grid {
    grid-template-columns: 1fr;
  }
  
  .directives-demo h2 {
    font-size: 1.75rem;
  }
}
</style>